﻿using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static DDS.IoT.Com.ComBase;

namespace DDS.IoT.Mqtt
{
    public class MqttClientService
    {
        private IMqttClient mqttClient;
        private MqttFactory factory;
        private List<MqttClientSubscribeOptions> subscribes = new List<MqttClientSubscribeOptions>();
        public string PushId { get; set; }
        public event PushData OnPushData;

        [Obsolete]
        public void MqttClientStart(string extendData, PushData onPushData)
        {
            var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(extendData);
            string server = obj.server;//
            int port = obj.port;//1883
            string username = obj.username;
            string password = obj.password;
            string clientId = obj.clientid;//"IoT_" +Guid.NewGuid().ToString("N")
            var optionsBuilder = new MqttClientOptionsBuilder()
                .WithTcpServer(server, port) // 要访问的mqtt服务端的 ip 和 端口号
                .WithCredentials(username, password) // 要访问的mqtt服务端的用户名和密码
                .WithClientId(clientId) // 设置客户端id
                .WithCleanSession(false)
                //.WithKeepAlivePeriod(TimeSpan.FromSeconds(20))
                .WithTls(new MqttClientOptionsBuilderTlsParameters
                {
                    UseTls = false  // 是否使用 tls加密
                });
            this.OnPushData = onPushData;
            var clientOptions = optionsBuilder.Build();
            factory = new MqttFactory();
            mqttClient = factory.CreateMqttClient();
            mqttClient.ConnectedAsync += _mqttClient_ConnectedAsync; // 客户端连接成功事件
            mqttClient.DisconnectedAsync += _mqttClient_DisconnectedAsync; // 客户端连接关闭事件
            mqttClient.ApplicationMessageReceivedAsync += _mqttClient_ApplicationMessageReceivedAsync; // 收到消息事件
            mqttClient.ConnectAsync(clientOptions);


        }
        public void Open() { 
        
        }
        public void Close() {
            mqttClient.DisconnectAsync();
            mqttClient.Dispose();
        }
        /// <summary>
        /// 客户端连接关闭事件
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        private Task _mqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs arg)
        {
            Console.WriteLine($"客户端已断开与服务端的连接……");
            //_mqttClient.ReconnectAsync();
            Task.Run(() => {
                Thread.Sleep(500);
                if (arg.ClientWasConnected||true)
                {
                    mqttClient.ConnectAsync(mqttClient.Options);
                }
            });
            return Task.CompletedTask;
        }

        /// <summary>
        /// 客户端连接成功事件
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        private Task _mqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg)
        {
            Console.WriteLine($"客户端已连接服务端……");
            Rescribe();
            // 订阅消息主题
            // MqttQualityOfServiceLevel: （QoS）:  0 最多一次，接收者不确认收到消息，并且消息不被发送者存储和重新发送提供与底层 TCP 协议相同的保证。
            // 1: 保证一条消息至少有一次会传递给接收方。发送方存储消息，直到它从接收方收到确认收到消息的数据包。一条消息可以多次发送或传递。
            // 2: 保证每条消息仅由预期的收件人接收一次。级别2是最安全和最慢的服务质量级别，保证由发送方和接收方之间的至少两个请求/响应（四次握手）。

            return Task.CompletedTask;
        }

        /// <summary>
        /// 收到消息事件
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        private Task _mqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            var payload = string.Empty;
            if (arg.ApplicationMessage.Payload != null)
            {
                payload = Encoding.UTF8.GetString(arg.ApplicationMessage.Payload);
            }
            Core.LogProvider.Default.Log(Infrastructure.Logging.LogLevel.Info, null, $"ApplicationMessageReceivedAsync：客户端ID=【{arg.ClientId}】接收到消息。 Topic主题=【{arg.ApplicationMessage.Topic}】 消息=【{payload}】 qos等级=【{arg.ApplicationMessage.QualityOfServiceLevel}】");
            if (OnPushData != null)
            {
                OnPushData(PushId, new { EventName = "Received", ClientId = arg.ClientId, Topic = arg.ApplicationMessage.Topic, Payload = payload });
            }
            return Task.CompletedTask;
        }
        public void Rescribe() {
            var arr = subscribes.ToArray();
            subscribes.Clear();
            foreach (var sub in arr) {
                Subscribe(sub.TopicFilters[0].Topic,(int)sub.TopicFilters[0].QualityOfServiceLevel);
            }
        }
        public bool Subscribe(string topic,int level) {
            var success = false;
            var canSub = false;
            if (subscribes.Exists(p => p.TopicFilters[0].Topic == topic)){
                return true;
            }
            for(var i = 0; i < 5; i++)
            {
                if (mqttClient.IsConnected)
                {
                    canSub = true;
                    break;
                }
                System.Threading.Thread.Sleep(300);
            }
            var mqttSubscribeOptions = factory.CreateSubscribeOptionsBuilder()
                .WithTopicFilter(
                    f =>
                    {
                        f.WithTopic(topic)
                        .WithQualityOfServiceLevel((MqttQualityOfServiceLevel)level);
                    })
                .Build();
            subscribes.Add(mqttSubscribeOptions);
            if (canSub)
            {
                mqttClient.SubscribeAsync(mqttSubscribeOptions);
                success = true;
            }
            else
            {
                // 超时
                //throw new Exception("订阅超时");
            }
            return success;
        }

        public bool Publish(string topic,string data,int level,bool retain)
        {
            var success = false;
            var canPub = false;
            for (var i = 0; i < 3; i++)
            {
                if (mqttClient.IsConnected)
                {
                    canPub = true;
                    break;
                }
                System.Threading.Thread.Sleep(500);
            }
            if (canPub)
            {
                var message = new MqttApplicationMessage
                {
                    Topic = topic,
                    Payload = Encoding.UTF8.GetBytes(data),
                    QualityOfServiceLevel = (MqttQualityOfServiceLevel)level,
                    Retain = retain  // 服务端是否保留消息。true为保留，如果有新的订阅者连接，就会立马收到该消息。
                };
                mqttClient.PublishAsync(message);
                success = true;
            }
            else
            {
                // 超时
                //throw new Exception("发布超时");
            }
            return success;
        }
    }
}
